[SECTION .text]
[bits 64]

extern kernel64_main
extern vsprintf
extern strlen
extern console_write

extern printk_buff

global _start
_start:
    xchg bx, bx
    xchg bx, bx

.init_8259a:
    ; 向主发送ICW1
    mov al, 11h
    out 20h, al

    ; 向从发送ICW1
    out 0a0h, al

    ; 向主发送ICW2
    mov al, 20h
    out 21h, al

    ; 向从发送ICW2
    mov al, 28h
    out 0a1h, al

    ; 向主发送ICW3
    mov al, 04h
    out 21h, al

    ; 向从发送ICW3
    mov al, 02h
    out 0A1h , al

    ; 向主发送ICW4
    mov al, 003h
    out 021h, al

    ; 向从发送ICW4
    out 0A1h, al

    ; 屏蔽所有中断，只接收键盘中断
.enable_8259a_main:
    mov al, 11111110b
    out 21h, al

    ; 屏蔽从芯片所有中断响应
.disable_8259a_slave:
    mov al, 11111101b
    out 0A1h, al

.enbale_rtc:
    mov al,0x0b                        ;RTC寄存器B
    or al,0x80                         ;阻断NMI
    out 0x70,al

    mov al,0x52                        ;设置寄存器B，开放周期性中断、更新结束后中断，BCD码，24小时制
    out 0x71,al

    mov al, 0x8a                             ;CMOS寄存器A
    out 0x70, al
    mov al, 0x2f                             ;32kHz，500ms的周期性中断
    out 0x71, al                             ;写回CMOS寄存器A

    ; 通过读，清零寄存器C，防止相关位被置位，导致对应的中断不再发生（非必须，稳妥写法）
    mov al,0x0c
    out 0x70,al
    in al,0x71

    in al,0xa1                         ;读8259从片的IMR寄存器
    and al,0xfe                        ;清除bit 0(此位连接RTC)
    out 0xa1,al                        ;写回此寄存器

    ; 每10ms发生一次时钟中断
.set_8253_frequency:
    mov al, 0x36         ; 设置PIT的工作模式
    out 0x43, al         ; 发送到控制端口

    mov ax, 11932        ; 为100Hz计算的除数
    out 0x40, al         ; 发送低字节到通道0
    mov al, ah
    out 0x40, al         ; 发送高字节到通道0

.end_kernel64_main:
    call kernel64_main

    jmp $

; rsi           <---rsp
; rdx
; rcx
; r8
; r9
; rdi
global printk
printk:
    cli

    push rdi
    push r9
    push r8
    push rcx
    push rdx
    push rsi

    ; 调用vsprintf(buff, fmt, p);
    mov rsi, rdi            ; fmt
    mov rdi, printk_buff    ; buff
    mov rdx, rsp            ; 第一个参数在栈中的地址
    call vsprintf

    ; 调用console_write(buff, strlen(buff))
    mov rdi, printk_buff
    call strlen

    mov rdi, printk_buff
    mov rsi, rax
    call console_write

    ; 栈还原
    add rsp, 8 * 6

    sti

    ret